package org.microframework.base.core.security.interceptor;

import org.microframework.base.core.security.context.SecurityContextHolder;
import org.microframework.base.core.security.exception.NotAuthorizedException;
import org.microframework.base.core.security.model.LoginUser;
import org.microframework.base.core.security.properties.SecurityProperties;
import org.microframework.base.core.security.token.TokenParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/**
 * 安全拦截器
 * 
 * 拦截请求，进行权限校验
 */
@Component
public class SecurityInterceptor implements HandlerInterceptor, Ordered {
    
    private static final Logger log = LoggerFactory.getLogger(SecurityInterceptor.class);
    
    /**
     * 令牌自定义标识
     */
    public static final String TOKEN_HEADER = "Authorization";
    
    /**
     * 令牌前缀
     */
    public static final String TOKEN_PREFIX = "Bearer ";
    
    /**
     * 路径匹配器
     */
    private final AntPathMatcher pathMatcher = new AntPathMatcher();
    
    @Autowired
    private SecurityProperties securityProperties;
    
    @Autowired
    private TokenParser tokenParser;
    
    /**
     * 拦截器优先级
     */
    private int order = Ordered.HIGHEST_PRECEDENCE + 200;
    
    @Override
    public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) throws Exception {
        // 检查是否启用拦截器
        if (!securityProperties.getInterceptor().isEnabled()) {
            return true;
        }
        
        // 获取请求路径
        String requestURI = request.getRequestURI();
        
        // 检查是否为排除路径
        if (isExcludePath(requestURI)) {
            return true;
        }
        
        // 如果不是处理方法，直接放行
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        
        // 获取请求头中的token
        String token = getToken(request);
        
        // 检查是否需要登录
        if (securityProperties.getInterceptor().isRequiresLogin()) {
            if (!StringUtils.hasText(token)) {
                log.warn("请求未提供Token: {}", requestURI);
                throw new NotAuthorizedException("未登录");
            }
            
            // 验证Token有效性
            if (!tokenParser.validateToken(token)) {
                log.warn("Token无效: {}", token);
                throw new NotAuthorizedException("Token无效或已过期");
            }
            
            // 提取用户信息并设置到上下文
            setLoginUserToContext(token);
        }
        
        // 检查是否需要进行权限校验
        if (securityProperties.getInterceptor().isEnablePermissionCheck()) {
            String permission = buildPermission(request);
            if (!SecurityContextHolder.hasPermission(permission)) {
                log.warn("用户无权限访问: {}, 需要权限: {}", requestURI, permission);
                throw new NotAuthorizedException("无权限访问");
            }
        }
        
        return true;
    }
    
    @Override
    public void afterCompletion(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler, @Nullable Exception ex) throws Exception {
        // 清理上下文
        SecurityContextHolder.clear();
    }
    
    /**
     * 检查是否为排除路径
     * 
     * @param requestURI 请求路径
     * @return 是否为排除路径
     */
    private boolean isExcludePath(String requestURI) {
        String[] excludePatterns = securityProperties.getInterceptor().getExcludePatterns();
        if (excludePatterns != null && excludePatterns.length > 0) {
            for (String pattern : excludePatterns) {
                if (pathMatcher.match(pattern, requestURI)) {
                    log.debug("匹配到排除路径: {}, 模式: {}", requestURI, pattern);
                    return true;
                }
            }
        }
        return false;
    }
    
    /**
     * 从请求中获取token
     * 
     * @param request 请求
     * @return token
     */
    private String getToken(HttpServletRequest request) {
        String token = request.getHeader(TOKEN_HEADER);
        if (StringUtils.hasText(token) && token.startsWith(TOKEN_PREFIX)) {
            token = token.substring(TOKEN_PREFIX.length());
        }
        return token;
    }
    
    /**
     * 从token中提取用户信息并设置到上下文
     * 
     * @param token 令牌
     */
    private void setLoginUserToContext(String token) {
        Long userId = tokenParser.getUserIdFromToken(token);
        String username = tokenParser.getUsernameFromToken(token);
        String realName = tokenParser.getRealNameFromToken(token);
        Boolean isAdmin = tokenParser.isAdminFromToken(token);
        
        if (userId != null && StringUtils.hasText(username)) {
            LoginUser loginUser = new LoginUser(userId, username);
            loginUser.setRealName(realName);
            loginUser.setAdmin(isAdmin != null && isAdmin);
            SecurityContextHolder.setLoginUser(loginUser);
            log.debug("设置用户到上下文: {}", username);
        }
    }
    
    /**
     * 构建权限标识
     * 
     * @param request 请求
     * @return 权限标识
     */
    private String buildPermission(HttpServletRequest request) {
        // 获取请求方法和路径
        String method = request.getMethod().toLowerCase();
        String requestURI = request.getRequestURI();
        
        // 移除前导斜杠
        if (requestURI.startsWith("/")) {
            requestURI = requestURI.substring(1);
        }
        
        // 替换所有斜杠为冒号
        requestURI = requestURI.replace('/', ':');
        
        // 构建权限标识
        String permissionPrefix = securityProperties.getInterceptor().getPermissionPrefix();
        if (StringUtils.hasText(permissionPrefix)) {
            return permissionPrefix + ":" + method + ":" + requestURI;
        } else {
            return method + ":" + requestURI;
        }
    }
    
    @Override
    public int getOrder() {
        return order;
    }
    
    public void setOrder(int order) {
        this.order = order;
    }
} 